#ifndef CHECKBOX_H
#define CHECKBOX_H

#include "label.h"
#include "../../images_manager.h"

#include <QPixmap>
#include <math.h>
#include <QRgb>
#include <QList>

class CheckBox;

class CheckBoxListener
{
public:
    virtual void OnCheckChange( CheckBox* sender, bool checked ) = 0;
};

class CheckBox: public Label
{
public:
    CheckBox(Widget* _parent, Engine* _engine, QString _text, int _x, int _y, int _w, int _h)
        :Label(_parent, _engine, _text, _x, _y, _w, _h), boxBrush(QColor(0, 0, 0, 0)), boxColor(0, 0, 0, 255),
         selectAnimation(_engine->fps, 150), om_ni(new Power_NI<float>(0.5), true)
    {
        brushAlpha = sq_dist = 0;
        press = false;

        approachGraph.AddSimpleProperty("bAlpha", brushAlpha, &invalidated);
        distProperty = approachGraph.AddSimpleProperty("sq_dist", sq_dist, &invalidated);
        approachGraph.AddInterpolator("sq_dist", 0, 5000, "bAlpha", 0, 255, &om_ni);

        imgWidth = 0;
        g.AddSimpleProperty("imgWidth", imgWidth, &invalidated);
        imgWidthInterpolatorId = g.AddInterpolator(selectAnimation.GetTime(), 0, 150, "imgWidth", 0, 0);
        engine->AddAnimation(&selectAnimation);
        selectAnimation.AddObserver(this);
        checked = false;

        SetFont(font);

        mouseTracking = true;
    }

    virtual ~CheckBox(){}

protected:

    virtual void Paint(QPainter& widgetPainter)
    {
        pixmap->fill(QColor(255, 255, 255, 0));
        QPainter painter(pixmap);

        // paints the background
        backColor.setRed(backBrushRed);
        backColor.setGreen(backBrushGreen);
        backColor.setBlue(backBrushBlue);
        backColor.setAlpha(backBrushAlpha);
        backBrush.setColor(backColor);
        painter.setBrush(backBrush);
        painter.setPen(QPen(QColor(0, 0, 0, 0)));
        painter.drawRect(-1, -1, w + 1, h + 1);

        // paints the text
        painter.setFont(font);
        color.setRed(penRed);
        color.setGreen(penGreen);
        color.setBlue(penBlue);
        color.setAlpha(penAlpha);
        pen->setColor(color);
        pen->setWidth(penWidth);
        painter.setPen(*pen);

        // calculates the text x and y position according to the chosen alignment
        int textX = boxSide + 7;
        switch(textAlignment)
        {
        case Left:
            textX += 0;
            break;
        case Right:
            textX = (w - textWidth);
            break;
        case Center:
            textX = w/2 - textWidth/2;
            break;
        }

        int textY = 0;
        switch(vertAlignment)
        {
        case Top:
            textY = textHeight;
            break;
        case Middle:
            textY = h - (h - textHeight)/2;
            break;
        case Bottom:
            textY = h;
            break;
        }
        painter.drawText(textX, textY, text);

        // paints the box
        boxColor.setGreen(brushAlpha);
        boxColor.setAlpha(brushAlpha * 0.1 * (press? 3 : 1));
        boxBrush.setColor(boxColor);
        painter.setBrush(boxBrush);
        painter.drawRoundedRect(0, tmp, boxSide, boxSide, 2, 2);

        // paints the check sign
        ImageUtils::BlendCheck(checkImage, penAlpha);

        if(imgWidth > 0)
        {
            painter.drawImage(-boxSide * 0.35, tmp - boxSide, checkImage, 0, 0, imgWidth, checkImage.height());
        }
        widgetPainter.drawPixmap(x, y, *pixmap, 0, 0, w, h);
    }

    virtual void doShow()
    {
        mouseTracking = true;
        Label::doShow();
    }

    virtual void doHide()
    {
        mouseTracking = false;
        Label::doHide();
    }

    virtual void OnEnd(Animation *a)
    {
        if(a == &selectAnimation)
        {
            checked = !a->IsReversed();
        }else
        {
            Label::OnEnd(a);
        }
    }

    virtual void OnMouseMoved(QMouseEvent *e, bool onWidget, int x_rel, int y_rel)
    {
        int d = pow(e->x() - boxCentreX, 2) + pow(e->y() - boxCentreY, 2);
        (*distProperty)(d);
    }

    virtual void OnMouseClick(QMouseEvent *e, int x_rel, int y_rel)
    {
        SetChecked( !checked, true );
    }

    virtual void OnMousePressed(QMouseEvent *e, bool inside, int x_rel, int y_rel)
    {
        press = inside;
    }

    virtual void OnMouseReleased(QMouseEvent *e, bool inside, int x_rel, int y_rel)
    {
        press = false;
    }

public:
    virtual bool IsChecked(){ return checked; }

    virtual void SetChecked( bool set, bool notifyListeners = true )
    {
        if(checked == set) return;
        mouseTracking = !set;

        if(set)
        {    
            selectAnimation.Stop();
        }else
        {    
            selectAnimation.Reverse(true);
        }

        if( notifyListeners )
        {
            for( int i=0; i<listeners.size(); i++ )
            {
                listeners[i]->OnCheckChange( this, set );
            }
        }

        selectAnimation.Play();
    }

    virtual void SetFont(const QFont &_font)
    {
        Label::SetFont(_font);

        // recalculates the box side and center
        tmp = (h - textHeight)/2;
        boxSide = h - 2 * tmp;
        boxCentreX = x + boxSide/2;
        boxCentreY = y + tmp + boxSide/2;

        // recalculates the check sign size
        QImage* original = ImagesManager::GetInstance()->GetImage(ImagesManager::CHECK);
        checkImage = original->scaled(boxSide * 2, boxSide * 2.5);
        g.Get(imgWidthInterpolatorId)->SetMaxY(checkImage.width());
    }

    void AddCheckBoxListener( CheckBoxListener* cbl )
    {
        listeners.append( cbl );
    }

    void RemoveCheckBoxListener( CheckBoxListener* cbl )
    {
        listeners.removeOne( cbl );
    }

    void ClearCheckBoxListeners( void )
    {
        listeners.clear();
    }

protected:
    QBrush boxBrush;
    QColor boxColor;
    int tmp, boxSide;
    int brushAlpha, sq_dist, boxCentreX, boxCentreY;

    bool checked;
    Animation selectAnimation;
    int imgWidth;
    int imgWidthInterpolatorId;

    IntGraph approachGraph;
    OneMinus_NI<float> om_ni;
    Property<int>* distProperty;

    QImage checkImage;
    QList< CheckBoxListener* > listeners;

private:
    bool press;
};


#endif // CHECKBOX_H
